/*
 * Universidad del Valle de Guatemala
 * Diseño de Lenguajes de Programación
 * Ing. Bidkar Pojoy
 * MAIN CLASS
 * @author: Melinton Navas - 09053
 */
package compilador;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;

/**
 *
 * @author Melinton
 */
public class Compilador {
    
    //--------------------------------------------------------------------------
    // ATRIBUTOS
    //--------------------------------------------------------------------------
    private static Scanner scanner;
    private static Loader loader;
    private static HashMap automatas;
    private static HashMap tokens;
    private static Automata autGeneral;
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws FileNotFoundException 
    {
        //procesarAutomatas
        automatas = new HashMap();
        try
        {
            loadInputFile("Ejemplo.txt");
        }
        catch(IOException e)
        {
            e.getMessage();
            System.exit(1);
        }
        try
        {
            escribirArchivo();
        }
        catch(Exception e)
        {
            e.getMessage();
        }
        
        Iterator it;
        String pivotKey = "";
        String pivotRegex = "";                               
        //Construccion de TOKENS
        it = loader.regTokens.keySet().iterator();
        while(it.hasNext())
        {
           pivotKey = (String) it.next();
           pivotRegex = (String) loader.regTokens.get(pivotKey);
           construirAutomata(pivotRegex, pivotKey);
        }
        //automataGeneral();
        
        //TODO - Simulacion Automatas independientes en var(automatas)
        File file = new File("SimulacionTokens.txt");
        Scanner scan = new Scanner(file);
        String archivo = scan.next();
        Iterator iter = automatas.keySet().iterator();  
        Automata pivotAut;
        tokens = new HashMap();
        String pivoteArchivo;
        while(iter.hasNext())
        {
            pivotKey = (String) iter.next();
            pivotAut = (Automata) automatas.get(pivotKey);
            pivoteArchivo = simulacionAFN(archivo, pivotAut, pivotKey);
            while(pivoteArchivo != "")
            {
                pivoteArchivo = simulacionAFN(pivoteArchivo, pivotAut, pivotKey);
            }
        }
        try
        {
            //escribirTokens();
        }
        catch(Exception e)
        {}               
        
        HashMap regexMetodos = new HashMap();
        
        
        HashMap metodosProducciones = loader.metodos;
        Iterator iterator = metodosProducciones.keySet().iterator();
        String pivKey;
        ArrayList pivValue;
        while(iterator.hasNext())
        {
            String pivoteMetodos = "";
            pivKey = (String) iterator.next();
            pivValue = (ArrayList) metodosProducciones.get(pivKey);
            
        }
        
        
        
        System.exit(0);       
    }
    
     public static String simulacionAFN(String w, Automata AFN, String tokenId)
    {        
        ArrayList<Estado> s_0 = new ArrayList();
        s_0.add(AFN.estadoInicial);
        ArrayList<Estado> s = AFN.cerraduraEpsilon(s_0);
        StringBuffer cadenaToken = new StringBuffer();
        boolean centinela = false;
        String cadenaPivote = "";
        for(int i = 0; i < w.length() && !centinela; i++)
        {
            s = AFN.cerraduraEpsilon(AFN.mover(s, w.charAt(i) + ""));
            if(!s.isEmpty())
                cadenaToken.append(w.charAt(i));
            else
            {
                centinela = true;
                cadenaPivote = w.substring(i);
                tokens.put(tokenId, cadenaToken.toString());
            }
            
        }        
        tokens.put(tokenId, cadenaToken.toString());
        return cadenaPivote;
        
        
        /*
        boolean centinela = false;
        for(int u = 0; u < s.size() && !centinela; u++)
        {
            for(int b = 0; b < AFN.estadosFinales.size() && !centinela; b++)
            {
                if(s.get(u).equals(AFN.estadosFinales.get(b)))                    
                    centinela = true;
            }
        }   */     
    }
    
    public static void escribirTokens() throws IOException
    {     
        FileWriter fWrite = new FileWriter("Tokens.txt");
        BufferedWriter writer = new BufferedWriter(fWrite);  
        Iterator it = tokens.keySet().iterator();
        String pivotKey;
        String pivotValue;
        while(it.hasNext())
        {
            pivotKey = (String) it.next();
            pivotValue = (String) tokens.get(pivotKey);
            writer.write(pivotKey + "\t" + pivotValue + '\n');
        }
        writer.close();
    }
    
    public static void automataGeneral()
    {
        Estado eInicialGeneral = new Estado("S0");
        Estado eFinalGeneral = new Estado("SN");
        Iterator it = automatas.keySet().iterator();
        autGeneral = new Automata(eInicialGeneral);
        autGeneral.anhadirEstadoFinal(eFinalGeneral);
        String pivotKey;        
        Automata pivotAut;
        Funcion pivotFun;
        while(it.hasNext())
        {
            pivotKey = (String) it.next();
            pivotAut = (Automata) automatas.get(pivotKey);
            pivotFun = new Funcion(eInicialGeneral, "¬", pivotAut.estadoInicial);            
            autGeneral.anhadirFuncion(pivotFun);
            autGeneral.estadosFinales.addAll(pivotAut.estadosFinales);
            for(int i = 0; i < pivotAut.estadosFinales.size(); i++)
            {
                pivotFun = new Funcion(pivotAut.estadosFinales.get(i), "¬", eFinalGeneral);
                autGeneral.anhadirFuncion(pivotFun);
            }
            autGeneral.estados.add(eInicialGeneral);
            autGeneral.estados.addAll(pivotAut.estados);
            autGeneral.funciones.addAll(pivotAut.funciones);
            autGeneral.anhadirAlLenguaje(pivotAut.lenguaje);
        }        
    }
    
    public static void loadInputFile(String path) throws IOException
    {
        /*Read input file*/
        BufferedReader f = new BufferedReader(new FileReader(path));
        loader = new Loader(f);
        loader.inputFile();
        f.close();
        loader.transformarRegex();
        //System.out.println(loader.darCadena());
        //System.exit(0);        
    }
    
    public static void construirAutomata(String regex, String pivotKey)
    {                
        Automata automata;
        ArrayList<String> leng;
        Parser parser;
        ArrayList array;
        Node arbol;           
        parser = new Parser();
        array = parser.convertirAPosfix(regex+'#');
        arbol = parser.crearArbol();
        leng = obtenerLenguaje(regex+'#');
        automata = parser.thompson(arbol, leng, null);//parser.construccionDirecta(arbol, leng);
        //automata = automata.toAFD();
        automatas.put(pivotKey, automata);        
    }
    
    public static void escribirArchivo() throws FileNotFoundException, IOException
    {
        FileReader f = new FileReader("Archivo.java.frame");
        CharBuffer input = new CharBuffer(f,3);
        FileWriter fWrite = new FileWriter("Compilador.java");
        BufferedWriter writer = new BufferedWriter(fWrite);       
        while(input.LA(1) != -1)
        {
            if((char) input.LA(1)=='-' && (char) input.LA(2) == '-' && (char) input.LA(3) == '>')
            {
                //Consumir la flecha
                input.consume();
                input.consume();
                input.consume(); 
                //Consumir REGEX
                input.consume();
                input.consume();
                input.consume(); 
                input.consume();
                input.consume();
                
                Iterator it;
                String pivotKey = "";
                String pivotRegex = "";                               
                //Construccion de TOKENS
                it = loader.regTokens.keySet().iterator();
                while(it.hasNext())
                {
                    pivotKey = (String) it.next();
                    pivotRegex = (String) loader.regTokens.get(pivotKey);
                    writer.write("\t construirAutomata(\"" + pivotRegex + "\");\n");
                }
            }               
                writer.write(input.LA(1));
                input.consume();            
        }                           
        writer.close();
    }
    
    public static void procesarAutomatas()
    {
        scanner = new Scanner(System.in);
        System.out.println("Ingrese expresion regular");
        String expReg = scanner.nextLine();
        System.out.println("Ingrese cadena de prueba");
        String cadenaPrueba = scanner.nextLine();
        expReg = sustituirOperaciones(expReg);
        Parser parser = new Parser();
        ArrayList array = parser.convertirAPosfix(expReg+"#");
        for(int i = 0; i<array.size(); i++)
        {
            System.out.print(array.get(i));
        }
        System.out.println();
        Node arbol = parser.crearArbol();
        ArrayList<String> leng = obtenerLenguaje(expReg);
        Automata aut = parser.thompson(arbol, leng, null);
        BTreePrinter.printNode(arbol);
        System.out.println(parser.simulacionAFN(cadenaPrueba, aut));

        System.out.println("AFN:");
        System.out.println("Estados: " + aut.estados.size());
        System.out.println("Funciones: " + aut.funciones.size());
        
        Automata afd = aut.toAFD();        
        System.out.println("AFD:");                
        System.out.println("Estados: " + afd.estados.size());
        System.out.println("Funciones: " + afd.funciones.size());
        //System.out.println("Estado final: " + afd.estadosFinales.get(0).valor);
        
        Automata afdDirecto = parser.construccionDirecta(arbol, leng);
        //boolean aceptado = parser.simulacionAFD(cadenaPrueba, afdDirecto);
        System.out.println("AFD-Directo:");               
        System.out.println("Estados: " + afdDirecto.estados.size());
        System.out.println("Funciones: " + afdDirecto.funciones.size());
        System.out.println("Estado final: " + afdDirecto.estadosFinales.get(0).valor);
        //System.out.println("Resultado: " + aceptado);
        scanner.close();
    }
    
    public static String sustituirOperaciones(String cadena)
    {                
        if(cadena.contains("+"))
        {            
            for(int i = 0; i < cadena.length(); i++)
            {
                if(cadena.charAt(i)=='+')
                {
                    String unoAntes = cadena.charAt(i-1)+"";
                    String cadenaRep = unoAntes +"*";                    
                    cadena = cadena.replaceFirst("\\+", cadenaRep);
                }
            }
        }               
        if(cadena.contains("?"))
        {
            cadena = cadena.replaceAll("\\?","|¬");
        }
        return cadena;
    }
    
    public static ArrayList<String> obtenerLenguaje(String cadena)
    {
        ArrayList<String> lenguaje = new ArrayList();
        for(int i = 0; i < cadena.length(); i++)
        {
            boolean centinela = false; 
            for(int u = 0; u < lenguaje.size() && !centinela; u++)
            {
                if(lenguaje.get(u).equals(cadena.charAt(i)+""))
                    centinela = true;
            }
            
            if(!centinela && (Character.isAlphabetic(cadena.charAt(i)) || cadena.charAt(i) == '¬'))
                lenguaje.add(cadena.charAt(i)+"");
        }
        
        return lenguaje;
    }
}
